perm filename DOC[PAT,LMM] blob sn#092640 filedate 1974-03-16 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00004 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	 USER DEFINED DATA TYPES
C00007 00003	ADDITIONAL NOTES:
C00021 00004	SUBRS FOR USER-DEFINED DATA TYPES
C00026 ENDMK
C⊗;
 USER DEFINED DATA TYPES

 We have  completed the initial  implementation of user  defined data
types  and have integrated  this package  with the RECORD  package of
CLISP.  This  allows the user to  specify data structures  containing
only what he  needs in a more  compact form,  and  with faster access
time, than  if list structures were used.  The storage allocation and
garbage collection of user defined data types is the  same as for any
regular LISP  data type,  and is therefore  just as efficient.   This
data definition facility is not completely general; for example,  not
all the data types that currently exist  in LISP are user defineable.
However,  it provides a  significant increase in  the data definition
capabilities of LISP.

  The scheme used  provides the ability  to define  fixed length data
types composed of fixed length  components.  Each component may be  a
pointer, an  integer,  a  floating point number,   or some  number of
bits. 

To declare a DATATYPE, enter the declaration:

	(DATATYPE name fields . defaults & subfields)

just like any other RECORD declaration.

For DATATYPE record  declarations, "fields" is  a list of  the fields
contained in the data type. Each field is of the form:

 field-name		the field is a pointer (i.e. you can store
(field-name POINTER)	any arbitrary LISP datum in this field)

(field-name BITS n)	the field is an n-bit unsigned integer.

(field-name BIT)	equivalent to ...BITS 1)

(field-name BYTE)	equivalent to ...BITS 7)

(field-name INTEGER)	the field is a full word signed integer.

(field-name FLOATING)	the field is a floating point number.

(field-name HALFWORD)   the field is a half word signed integer.

{INT=FIXP=INTEGER, REAL=FLOAT=FLOATING, ATOM=PTR=POINTER,
HALF=HALFWORD are all allowable synonyms }.

DATATYPEs differ  from other  types of  records in  that the  garbage
collector  must be made aware  of them explicitly,  separate pages of
the LISP  address space  must be  allocated for  data  of this  type;
further, as in TYPERECORD's, there must be a unique identifier (atom)
which is common among all data types.

Thus, the "name" portion of a DATATYPE declaration may be 
	(RECORDNAME DATATYPENAME)
where RECORDNAME is the name used in  CREATE and TYPE? expressions as
well as  for identification in RECORDS prettycoms; while DATATYPENAME
must be  a unique  identifier which  is common  to  local and  global
declarations which  expect to  access datum  of this  type. Normally,
"name" is both the RECORDNAME and the DATATYPENAME.

DATATYPE declarations can have subfields and  default values, and can
BE sub-declarations  to other record declarations. Currently no error
checking  is done  to  insure  that  numeric  fields  are  not  given
subfields (other than ACCESSFN subfields).

ADDITIONAL NOTES:

An additional feature of  the RECORD package is the  TYPE? statement:
an expression of the form

(TYPE? recordname expr)

will be  translated to  the appropriate  expression to  check if  the
value of "expr"  is of the type "recordname".  This is implemented if
"recordname" is a DATATYPE or a TYPERECORD -- all other  record types
will cause an error at translation time.

----------------------------------------------------------------------

The  allocation of  space  within a  datum  of a  given  type is  not
necessarily  in   the  order  that  the  fields   are  given  in  the
declaration: viz.

(DATATYPE MESSAGE ((LENGTH BIT 4) (HEADER POINTER) (COUNT HALF) (DATE
BIT 12]

here, the actual representation of a MESSAGE would be:

 bit:	0		  17 18  21 22    33 34 35
	------------------------------------------
	|	header	    |length|  date  |un- |   word 1
	|		    |	   |	    |used|
	------------------------------------------
	|	count	    |	   unused	 |    word 2
	|		    |			 |
	------------------------------------------


----------------------------------------------------------------------
Currently, the DATATYPE part of the record package is not included in
the file RECORD.COM but is in the file RECORDSTRUC.COM; thus after 

(DATATYPE MESSAGE ((TIME REAL) (UNITS INTEGER) HEADER TRAILER)
	TIME←(CLOCK 0]

you will first get the query:

  Shall I load RECORD.COM? ...Yes

and then
  Shall I load RECORDSTRUC.COM? ...Yes

RECORDSTRUC contains  a  minimal amount  of interface  to the  record
package, but MAINLY all of the functions and macros for accessing and
storing in data-types.
----------------------------------------------------------------------

Since  a  DATATYPE  need  be  allocated   even  when  no  translating
information  is  necessary, the  RECORDS* prettymacro  prints  out an
ALLOCATESTRUC  expression that  IS  copied  to  the  .COM  file  upon
compilation.  This is  so  files with  DATATYPE  declarations can  be
compiled  and loaded  and run without  loading the  entire RECORD and
RECORDSTRUC files.

SUBRS FOR USER-DEFINED DATA TYPES

DEFTYPE[nwrds; nptrs]

 Defines a new data type such that each object of that type has nwrds
words  and  nptrs pointers  within  those  nwrds.   If  there  are no
available types, an attempt  is made to find  a data type which  has;
(1) the proper number of pointers,  (2) at least the needed number of
words,   and (3) has been marked as "not in use" via TYPESTATUS.  The
data type number selected is returned as the value of DEFTYPE.

GETNPTRS[typen]

 Returns the number of pointers in an object whose type is typen.

GETNWRDS[typen]

 Returns the number of words in a object whose type is typen.

NALLOC[typen]

 Allocates an object of type typen,  clears its  contents to zero and
returns a pointer to it.

USERCONS[typen; p1; p2; ...  ; pn]

 Similar to  NALLOC but fills in the pointers  within the object with
the arguments p1, p2, ...  ,   pn.  If too many arguments are  given,
the extra ones are ignored.  If too few arguments are given, NILs are
supplied.

TYPESTATUS[typen; status]

  Sets  the status  of  data type  typen  to status  and  returns the
previous status.   If status  is NIL,   the status of  typen is  left
unchaged.  The meaning of the status is as follows:

Status = 0 - the data type has never been used.

	= 1 - the  data type is currently in use.   The status is set
to 1 by DEFTYPE when it selects a type.

	=  2 - the type was previously in  use,  but is now available
for selection by DEFTYPE if no other types are available.

Actually,  a status value of 1 is the only  value DEFTYPE checks for.
It is advisable to set the  status to 2, instead of 0, when freeing a
data type,  simply to distinguish between "not in use" and "has never
been in use".

DEFEVAL[typen; fn]

	Defines how the data type typen is to be evaluated. When EVAL
tries to  evaluate an item of  type typen,  it will  call fn with the
item as its argument.  The  result returned by fn is then the  result
of the evaluation.   If typen is not a valid type number,   or if the
type  number is that of  lists, litatoms,  or  numbers,  then DEFEVAL
simply returns NIL.  If fn is T or EVAL,  the  evaluation is reset to
the  default where the  items of  the given  type simply  evaluate to
themselves.  If fn is NIL,   the evaluation function is not  changed,
and the current one, for that type, is returned.

For  compatibility  with  the  compiler,     there  is  the  variable
COMPILETYPELST.  COMPILETYPELST is an a-list of type-number, function
pairs.  When  an attempt is made  to compile code  for an item  whose
type  number  is on  COMPILETYPELST,    the  item  is passed  to  the
corresponding  function.   The  result from  the  function,   as with
macros, is then compiled in place of the original item.  Like macros,
the  function  may  call  compiler  functions  itself,    and  return
INSTRUCTIONS.

For example,   (24  .   (LAMBDA(X) <'PRINT  (KWOTE X)>))  will  cause
unquoted strings  to be  compiled as a  call to  PRINT.  The  DEFEVAL
equivalent is DEFEVAL(24 PRINT).